haproxy 实现七层动静分离和负载均衡

前言

一般web网站请求大致分为两类: ajax动态请求和静态资源请求(css, js, 图片资源及视频资源等)。而nginx是处理静态资源的一大神器,开启sendfile机制,使用linux内核提供的零拷贝技术,减少资源文件在用户态和内核态之间的内存拷贝和上下文切换带来的性能开销,并支持反向代理,可以很方便的控制静态资源文件缓存有效期等。同时利用tomcat应用服务器的特性,处理动态请求,比如ajax请求,http接口请求等,然后在流量接入层利用haproxy做动静分离和负载均衡,将动态请求分流到tomcat应用服务器集群,将静态资源请求分流到nginx静态资源服务器集群。

部署方案

网络结构图:
image

haproxy 配置如下:

frontend http-in
bind *:80
option http-keep-alive
timeout http-keep-alive 30s
log global

acl lpp_web path_beg -i /lpp-web
acl uri_src path_reg -i ^/.+\.(js|css|ico|gif|bmp|jpg|jpeg|png|swf|cur)$
use_backend static_servers if lpp_web uri_src //都为true则走静态资源服务器
default_backend dynamic_servers //默认走dynamic_servers服务器集群

frontend https-in
bind *:443 ssl crt /usr/local/haproxy/conf/pandan.xyz.pem ciphers HIGH:!aNULL:!MD5
option http-keep-alive
timeout http-keep-alive 30s
log global

acl lpp_web path_beg -i /lpp-web
acl uri_src path_reg -i ^/.+\.(js|css|ico|gif|bmp|jpg|jpeg|png|swf|cur)$
use_backend static_servers if lpp_web uri_src //都为true则走静态资源服务器
default_backend dynamic_servers //默认走dynamic_servers服务器集群

//nginx静态资源服务器集群
backend static_servers
mode http
balance source
option httpchk GET /lpp-web/monitor.html
server resource_nginx115 10.116.84.115:800 cookie resource_nginx115 check inter 3000 rise 3 fall 3 weight 1
server resource_nginx116 10.116.84.116:800 cookie resource_nginx116 check inter 3000 rise 3 fall 3 weight 1
http-request add-header X-Forwarded-Proto https if { ssl_fc } //如果是https请求,则添加一个请求头,告诉后端服务器请求的协议类型,否则后端服务器是无法感知具体请求协议的

//tomcat应用服务器集群
backend dynamic_servers
mode http
balance source
option httpchk GET /lpp-web/monitor.html
server app_tomcat112 10.116.84.112:800 cookie app-tomcat112 check inter 3000 rise 3 fall 3 weight 1
server app_tomcat109 10.116.84.109:800 cookie app-tomcat109 check inter 3000 rise 3 fall 3 weight 1
http-request add-header X-Forwarded-Proto https if { ssl_fc } //如果是https请求,则添加一个请求头,告诉后端服务器请求的协议类型,否则后端服务器是无法感知具体请求协议的

nginx 配置如下:

http {
sendfile on;
keepalive_timeout 30s;

gzip on;
gzip_comp_level 4;

client_max_body_size 8m;
client_body_buffer_size 128k;

client_header_buffer_size 16k;
large_client_header_buffers 4 32k;

proxy_buffer_size 16k;
proxy_buffers 8 32k;
proxy_busy_buffers_size 64k;

server {
listen 800;
server_name localhost;
access_log logs/resource.access.log main if=$loggable;

location ~ ^/.+\.(ico|gif|bmp|jpg|jpeg|png|swf|cur)$ {
root /usr/local/tomcat/app_tomcat112/webapps; //指向工程资源文件根目录
expires 15d; //告诉客户端浏览器缓存15天
}
}
}

总结与思考

总结:

为了方便部署,减少运维成本,我们采用的还是将web网站整个工程都部署在tomcat中(并没有将工程中的静态资源文件单独剥离,这也是方便开发和运维),然后在同一个服务器下,即安装nginx服务,也安装了tomcat服务。配置nginx的静态资源目录为tomcat所在目录下的webapps中工程资源目录。但是,由于浏览器的并发请求数是针对同一域名进行限制的,即同一时间针对同一域名下的请求有一定数量限制,超过限制数目的请求会被阻塞。所以,静态资源服务器都有自己的单独的域名,一来可以增大并发请求数,二来可以减少不必要的cookie信息的携带传输,消耗不必要的带宽等。

思考:

通过分析上述网络结构图,不难发现haproxy流量接入层是个单点,是整个集群的流量入口,当流量比较大时,也会成为性能的瓶颈所在,一旦该haproxy服务宕机,会导致整个集群无法对外提供服务,并不满足大型网站架构的高可用特性。

常见替代方案如下:

  • 方案1(haproxy + keepalived + nginx + tomcat)
    image
    在上述架构方案中,加入一个keepalived服务,keepalived是虚拟路由冗余协议的一种实现,可以实现双机浮动的虚拟IP(VIP),通过在两台服务器上部署haproxy服务,并且每台服务器上安装keepalived服务,用于相互检测haproxy服务是否可用,如果发现主服务不可用,则动态修改虚拟VIP对应的物理mac地址为备haproxy服务器的mac地址,从而实现一个高可用架构,缺点是有一个冗余的haproxy服务器处于闲置状态,没有对服务器资源充分利用。

  • 方案2(LVS/DR + keepalived + ngnix + tomcat)

    可以采用LVS/DR + keepalived + ngnix + tomcat架构来实现负载均衡和高可用流量接入层架构,直接通过nginx实现动静分离和应用服务器负载均衡,利用keepalived的虚拟路由冗余协议实现双机浮动的高可用架构,利用LVS/DR模式作为流量接入层负载均衡,LVS/DR和haproxy的区别是LVS/DR通过在数据链路层动态修改请求包中的目标mac地址,来达到流量的负载均衡,并且请求响应是由真实处理的nginx服务器直接返回给客户端,而不用经过LVS/DR负载器再返回给客户端;而haproxy做接入层负载,则完全是请求代理的方式,客户端所有的请求和响应都需要经过haproxy,当请求并发量很大时,haproxy就会成为性能的瓶颈(受限于单台haproxy服务器端口数,文件描述符,内存,cpu,磁盘I/O,网卡带宽等限制)。